﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Automation.Provider;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace System.Windows.Automation.Peers
{
    /// <summary>
    /// Implements extensions for <see cref="WindowAutomationPeer"/> class.
    /// </summary>
    public static class AutomationPeerExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TType"></typeparam>
        /// <param name="peer"></param>
        /// <param name="evaluator"></param>
        /// <returns></returns>
        public static TType FindProvider<TType>(this AutomationPeer peer, Func<AutomationPeer, bool> evaluator)
            where TType : AutomationPeer
        {
            Contract.Requires<ArgumentNullException>(peer != null, "peer");
            Contract.Requires<ArgumentNullException>(evaluator != null, "evaluator");

            var child = FindProvider(peer,evaluator);
            if (null == child)
                throw new ArgumentException("No child found that matches given evaluator!");
            
            var typedChild = (TType)child;
            if (null == typedChild)
                throw new ArgumentException("Child 'name' is not of type '" + typeof(TType).Name + "'!");

            return typedChild;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="peer"></param>
        /// <param name="evaluator"></param>
        /// <returns></returns>
        public static AutomationPeer FindProvider(this AutomationPeer peer, Func<AutomationPeer,bool> evaluator)
        {
            Contract.Requires<ArgumentNullException>(peer != null, "peer");

            var children = peer.GetChildren();
            
            if (null == children)
                return null;

            var untypedChild = children.FirstOrDefault( evaluator );
            if (untypedChild == null)
            {
                foreach (var child in children)
                {
                    untypedChild = FindProvider(child, evaluator);
                    if (null != untypedChild)
                        return untypedChild;
                }
            }
            return untypedChild;
        }

        /// <summary>
        /// Dumps information about the <see cref="AutomationPeer"/> and of its children up to the 
        /// degree defined by levelOfAncestor.
        /// </summary>
        /// <param name="peer"></param>
        /// <param name="levelOfAncestors"></param>
        public static void Dump(this AutomationPeer peer, int levelOfAncestors)
        {
            Contract.Requires<ArgumentNullException>(peer != null, "peer");

            Dump(peer);

            var children = peer.GetChildren();

            if (null == children || levelOfAncestors == 0)
                return;

            Trace.Indent();
            foreach (var child in children)
            {
                Dump(child, levelOfAncestors - 1);
            }
            Trace.Unindent();
        }

        /// <summary>
        /// Dumps information of the passed <see cref="AutomationPeer"/>.
        /// </summary>
        /// <param name="peer"></param>
        public static void Dump(this AutomationPeer peer)
        {
            var msg = string.Format("{0} - {1} - {2}",
                peer.GetAutomationId() ?? "", peer.GetClassName() ?? "", peer.GetName() ?? "");
            Trace.WriteLine(msg);
        }
    }

        /// <summary>
    /// Implements extensions for <see cref="ButtonAutomationPeer"/> class.
    /// </summary>
    public static class ButtonAutomationPeerExtensions
    {
        /// <summary>
        /// Simulates a click on the button.
        /// </summary>
        /// <param name="peer"></param>
        public static void Click(this ButtonAutomationPeer peer)
        {
            peer.SetFocus();
            ((IInvokeProvider)peer).Invoke();
        }
    }
}